package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type Queue struct {
	queue []string
	cond  *sync.Cond
}

func main() {
	queue := &Queue{
		queue: []string{},
		cond:  sync.NewCond(&sync.Mutex{}),
	}

	go func() {
		for i := 0; i < 100; i++ {
			queue.Enqueue(strconv.Itoa(i))
			time.Sleep(2 * time.Second)
		}
	}()

	for {
		queue.Dequeue()
		time.Sleep(time.Second)
	}
}

func (q *Queue) Enqueue(item string) {
	q.cond.L.Lock()
	defer q.cond.L.Unlock()

	q.queue = append(q.queue, item)
	fmt.Println("Enqueue: ", item)
	q.cond.Broadcast()
}

func (q *Queue) Dequeue() string {
	q.cond.L.Lock()
	defer q.cond.L.Unlock()

	for len(q.queue) == 0 { // wait 函数被唤醒时，存在虚假唤醒等情况，导致唤醒后发现，条件依旧不成立。因此需要使用 for 语句来循环地进行等待，直到条件成立为止。因此不使用if
		q.cond.Wait()
	}
	result := q.queue[0]
	q.queue = q.queue[1:]
	fmt.Println("Dequeue: ", result)
	return result
}
